import { asyncLoadGLTFData } from './system/asyncGLTFLoader.js'
import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils.js'
import * as THREE from 'three'
import { SetObject3DParamFromJsonEle } from './jsonToObjec3d.js'
import {mittTypes} from "@/util/types"
import { modelCacheManager } from '@/utils/modelCacheManager'

// 检测是否为iOS移动端
function isIOSMobile() {
  const userAgent = navigator.userAgent || navigator.vendor || window.opera;
  return /iPad|iPhone|iPod/.test(userAgent) ;
}

var roleModelList = new Map()

var Role = function (jsonEle, scene,camera,loop,emitter) {

  var _this = this;
  this.jsonEle = jsonEle
  var root = scene

  console.log('role json:', jsonEle)
  this.titleSprite = null


  if (jsonEle.enable == false) {
    return
  }
  const crossFadeControls = []
  
  const allActions = []
  const allMouseActions = []
  const otherActions = []
  const allExtraActions = []
  let curAction
  const baseActions = {
    idle: { weight: 1 },
    walk: { weight: 0 },
    run: { weight: 0 },
    Move_L:{weight:0},
    Move_L_2:{weight:0},
    Move_L_3:{weight:0},
    Move_R:{weight:0},
    Move_R_2:{weight:0},
    Move_R_3:{weight:0},
  }
  const additiveActions = {
    eye: { weight: 1 },
    eyelash: { weight: 1 },
  }
  var sound, analyser;
  let mouseMoves = [
    { time: 50, id: 0 },
    { time: 100, id: 15 },
    { time: 225, id: 1 },
    { time: 275, id: 19 },
    { time: 350, id: 14 },
    { time: 400, id: 4 },
    { time: 475, id: 6 },
    { time: 512, id: 19 },
    { time: 550, id: 1 },
    { time: 575, id: 1 },
    { time: 612, id: 21 },
    { time: 662, id: 4 },
    { time: 712, id: 6 },
    { time: 787, id: 12 },
    { time: 831, id: 7 },
    { time: 875, id: 2 },
    { time: 950, id: 19 },
    { time: 1062, id: 21 },
    { time: 1087, id: 6 },
    { time: 1112, id: 1 },
    { time: 1187, id: 20 },
    { time: 1237, id: 21 },
    { time: 1250, id: 7 },
    { time: 1262, id: 7 },
    { time: 1287, id: 7 },
    { time: 1325, id: 16 },
    { time: 1368, id: 6 },
    { time: 1424, id: 2 },
    { time: 1478, id: 20 },
    { time: 1575, id: 19 },
    { time: 1625, id: 7 },
    { time: 1675, id: 7 },
    { time: 1812, id: 20 },
    { time: 1875, id: 0 },
    { time: 2150, id: 7 },
    { time: 2200, id: 8 },
    { time: 2236, id: 8 },
    { time: 2300, id: 19 },
    { time: 2343, id: 15 },
    { time: 2387, id: 6 },
    { time: 2425, id: 6 },
    { time: 2500, id: 16 },
    { time: 2537, id: 7 },
    { time: 2575, id: 4 },
    { time: 2612, id: 4 },
    { time: 2662, id: 19 },
    { time: 2700, id: 1 },
    { time: 2725, id: 1 },
    { time: 2762, id: 19 },
    { time: 2825, id: 2 },
    { time: 2850, id: 2 },
    { time: 2887, id: 21 },
    { time: 2925, id: 1 },
    { time: 2962, id: 19 },
    { time: 3000, id: 19 },
    { time: 3062, id: 15 },
    { time: 3125, id: 2 },
    { time: 3187, id: 8 },
    { time: 3262, id: 19 },
    { time: 3337, id: 2 },
    { time: 3425, id: 8 },
    { time: 3525, id: 0 },

  ]
  let actionFinCallback = null;
  let mouseData = null;
  const fadeTime = 0.2;
  const mouseActions = {
    '0': { weight: 0 },
    '1': { weight: 0 },
    '2': { weight: 0 },
    '3': { weight: 0 },
    '4': { weight: 0 },
    '5': { weight: 0 },
    '6': { weight: 0 },
    '7': { weight: 0 },
    '8': { weight: 0 },
    '9': { weight: 0 },
    '10': { weight: 0 },
    '11': { weight: 0 },
    '12': { weight: 0 },
    '13': { weight: 0 },
    '14': { weight: 0 },
    '15': { weight: 0 },
    '16': { weight: 0 },
    '17': { weight: 0 },
    '18': { weight: 0 },
    '19': { weight: 0 },
    '20': { weight: 0 },
    '21': { weight: 0 },
  }
  let transMap = new Map()
    transMap.set(0,'M_B_P')
    transMap.set(1,'A')
    transMap.set(2,'A')
    transMap.set(3,'O')
    transMap.set(4,'E')
    transMap.set(5,'E')
    transMap.set(6,'E')
    transMap.set(7,'W_R')
    transMap.set(8,'O')
    transMap.set(9,'A')
    transMap.set(10,'O')
    transMap.set(11,'A')
    transMap.set(12,'E')
    transMap.set(13,'O')
    transMap.set(14,'L_N')
    transMap.set(15,'T_S')
    transMap.set(16,'T_S')
    transMap.set(17,'E')
    transMap.set(18,'F_V')
    transMap.set(19,'T_S')
    transMap.set(20,'A')
    transMap.set(21,'M_B_P')
  let curMouse = null;
  let curMouseIndex = 0;
  let speaking = false;
  let mouseTime = 0.0;
  let speakDataList = [];
  let speakDataIndex = 0;
  let messageData = null;
  let audioElementList = null;
  let currentAudioElement = null;
  let mixerEnable = true;

  let oldFr = 0;
  let oldAction = null;

  let currentBaseAction = 'idle'
  var mixer
  let numAnimations
  this.model = undefined
  var scope = this

  function transActionById(id){
    
    let name = transMap.get(id)
    for(var i=0;i<allMouseActions.length;i++){
      if(allMouseActions[i]._clip.name == name){
        return allMouseActions[i]
      }
    }

  }

  this.setRoleInfo = function(data){
    this.jsonEle = jsonEle = data
  }


  var previousAction, activeAction

  this.loadGl = async function () {
    // document.getElementById('loading').style.display = 'block';
    if(this.model){
      this.model.visible = false;
    }
    //兼容绝对地址
    // if (jsonEle.url && jsonEle.url.indexOf(import.meta.env.VITE_APP_RESOURCE_REQUEST_URL) < 0) {
    //   jsonEle.url = import.meta.env.VITE_APP_RESOURCE_REQUEST_URL + jsonEle.url
    // }
    // jsonEle.url = 'https://aiimg.huilan.com/material/model/bucket-000000/1770991377771941889.glb'
    var model, gltfData
    var actionData = []
        jsonEle.url = jsonEle.url.replace('aimeta.huilan.com:32108','aimetacdn.huilan.com')
    
    // 检查是否已经缓存，避免重复预加载（iOS移动端跳过缓存）
    if (!isIOSMobile()) {
      const isCached = await modelCacheManager.isModelCached(jsonEle.url)
      if (!isCached) {
        try {
          await modelCacheManager.preloadModel(jsonEle.url)
        } catch (error) {
          console.warn('Failed to preload model to cache:', jsonEle.url, error)
        }
      }
    }
    

    //增加角色列表，如果已加载的直接克隆
    if (roleModelList.has(jsonEle.url)) {
      model = SkeletonUtils.clone(roleModelList.get(jsonEle.url).scene)
      console.log('克隆角色:', jsonEle.url)
      gltfData = roleModelList.get(jsonEle.url)
    } else {
      gltfData = await asyncLoadGLTFData(jsonEle.url,function(percent){
        // let loadbarWidth = document.getElementById('progress-loader').clientWidth
        // document.getElementById('loadProgress').style.width = percent/100 * loadbarWidth + 'px'
        emitter.emit(mittTypes.LOADING.UPDATE_LOADING_PROGRESS,Math.floor(percent*50/100))
      })
      //已加载数据
      let loaded = []
      let data = []
      // 加载数字人配置动画
      for(var i = 0;i<jsonEle.actionList.length;i++){
        let url = jsonEle.actionList[i].url
        let index =  loaded.findIndex(element => element.url == url)
        if(index<0&&url.indexOf('.glb')>=0){
          //加载新数据
          data = await asyncLoadGLTFData(url,function(percent){
            // let loadbarWidth = document.getElementById('progress-loader').clientWidth
            // document.getElementById('loadProgress').style.width = percent/100 * loadbarWidth + 'px'
            emitter.emit(mittTypes.LOADING.UPDATE_LOADING_PROGRESS,Math.floor(50+percent*49/100))
          })
          loaded.push({
            url:url,
            data:data
          });
          
          
        }else if(url.indexOf('.glb')>=0){
          // 已加载数据
          data = loaded[index].data
        }
        let animIdx = data.animations.findIndex(animation => animation.name == jsonEle.actionList[i].name)
        if(animIdx>=0){
          // 找到此名称的动画
          actionData.push(data.animations[animIdx])
        }else{
          
        }
        
      }
      
      model = SkeletonUtils.clone(gltfData.scene)
      roleModelList.set(jsonEle.url, gltfData)
      console.log('从文件加载角色:', jsonEle.url)
    }

    // var gltfData= await asyncLoadGLTFData(jsonEle.url);
    // var model=gltfData.scene;
    model.frustumCulled = false
    if(scope.model){
      root.remove(scope.model)
    }
    scope.model = model
    
    root.add(model)

    if (jsonEle.name) {
      scope.setTitle(jsonEle.name, 1.9)
    }

    model.castShadow = true;
    model.reciveShadow = true;
    model.traverse(function (object) {
      if (object.isMesh) {
        object.castShadow = true
        object.reciveShadow = true
        object.frustumCulled = false
      }
      if ( object.material ) {

        object.material.needsUpdate = true;

      }
    })
    
    SetObject3DParamFromJsonEle(model, jsonEle)

    mixer = new THREE.AnimationMixer(model)
    mixer.addEventListener('finished', function(e) {
      // console.log(e)
      setWeight(e.action, 0);
      // e.action.setLoop(THREE.LoopRepeat);
      e.action.stop();
      
      if(actionFinCallback){
        actionFinCallback(e.action);
      }
    });
    const animations = gltfData.animations
    this.roleAnimations = animations;
    console.log('role animations:', animations)
    numAnimations = animations.length
    for (let i = 0; i !== numAnimations; ++i) {
      let clip = animations[i]
      const name = clip.name

      if (baseActions[name]) {
        //基础动画 走 跑 站立
        const action = mixer.clipAction(clip)
        activateAction(action)
        baseActions[name].action = action
        allActions.push(action)
        curAction = baseActions['idle'].action;
      } else if (additiveActions[name]) {
        // Make the clip additive and remove the reference frame
        //面部动画 眼睛 眼睫毛
        THREE.AnimationUtils.makeClipAdditive(clip)

        if (clip.name.endsWith('_pose')) {
          clip = THREE.AnimationUtils.subclip(clip, clip.name, 2, 3, 30)
        }
        
        const action = mixer.clipAction(clip)
        activateAction(action)
        additiveActions[name].action = action
        allActions.push(action)
      }else if(mouseActions[name]){
        //口型动画 
        const action = mixer.clipAction(clip)
        activateAction(action)
        mouseActions[name].action = action
        allActions.push(action)
        allMouseActions.push(action)
      }else{
        //其他动画
        const action = mixer.clipAction(clip)
        activateAction(action)
        if(!additiveActions[name]){
          additiveActions[name] = {weight:0}
        }
        additiveActions[name].action = action
        allActions.push(action)
      }
    }
    //数字人配置动作动画
    const extraAnimations = actionData;
    for (let i = 0; i !== extraAnimations.length; ++i) {
      let clip = extraAnimations[i]
      const name = clip.name

      // if (additiveActions[name]) {
      //   // Make the clip additive and remove the reference frame

        
      // }
      THREE.AnimationUtils.makeClipAdditive(clip)

      if (clip.name.endsWith('_pose')) {
        clip = THREE.AnimationUtils.subclip(clip, clip.name, 2, 3, 30)
      }
      
      const action = mixer.clipAction(clip)
      activateAction(action)
      if(!additiveActions[name]){
        additiveActions[name] = {weight:0}
        additiveActions[name].action = action
        allActions.push(action)
      }
      
    }
    activeAction = baseActions['idle'].action
    if(activeAction){
      activeAction.play()
    }
    
    this.model.add(camera);
    camera.up.fromArray([0, 1, 0]);
    // camera.layers.disable(0)
    // camera.layers.enable(1)

    // this.model.traverse(function (child) {
    //   child.layers.set(1)
    // })

    this.chatCamera = camera;

    ////////////////离近播放的判断所用
    scope.posAngle = 180
    scope.lastPosAngle = scope.posAngle
    scope.posDir = new THREE.Vector3()
    scope.distance = 10
    scope.bNearToPlay = false
    scope.dirAngle = 180
    scope.meshDir = new THREE.Vector3(0, 0, 0)

    scope.lastAngle = scope.dirAngle
    this.model.getWorldDirection(scope.meshDir)

    scope.meshPosDir = scope.meshDir.clone()
    scope.meshPosDir.y = 0

    scope.meshPosition = new THREE.Vector3()
    this.model.getWorldPosition(scope.meshPosition)
    // document.getElementById('chatbox').style.visibility = 'visible';
    this.model.visible = true;
    document.getElementById('loading').style.display = 'none';
    emitter.emit(mittTypes.LOADING.LOAD_FINISH)
  }


  // var gltfData=load(jsonEle.url);

  this.init = async function () {
    const listener = new THREE.AudioListener();
	  camera.add(listener);
    sound = new THREE.Audio(listener);


    await this.loadGl()

    
    //////////////////////////////////////////////////////////测试
    // document.addEventListener('keydown', OnKeyDown)

    loop.updatables.push(scope)
    //play("walk");

    
    
    
    // document.getElementById('bottomShadow').style.display = 'block';
  }

  //////////////////////////////////////////////////////////测试
  // document.addEventListener('keydown', OnKeyDown);

  function OnKeyDown(e) {
    let bGo = false
    if (e.key == 'R' || e.key == 'r') {
      play('idle')
    } else if (e.key == 'T' || e.key == 't') {
      // play('agree')
      fadeActionWeight('agree', 1,0.35)
    } else if (e.key == 'Y' || e.key == 'y') {
      // play('headShake')
      fadeActionWeight('headShake', 1,0.35)
    } else if (e.key == 'U'||e.key=='u') {
      // play('sneak_pose')
      fadeActionWeight('sneak_pose', 1,0.35)
    }else if (e.key == 'I'||e.key=='i') {
      // play('sad_pose')
      fadeActionWeight('sad_pose', 1,1)
    }else if (e.key == 'O'||e.key=='o') {
      // play('sad_pose')
      fadeActionWeight('sad_pose', 0,0.35,false);
      fadeActionWeight('agree', 0,0.35,false);
      fadeActionWeight('headShake', 0,0.35,false);
      fadeActionWeight('sneak_pose', 0,0.35,false);
    }
    
  }

  this.walk = function () {
    play('walk')
  }
  this.run = function () {
    play('run')
  }
  this.idle = function () {
    play('idle')
  }

  function play(name) {
    fadeToAction(name, 0.35)
  }
  function stopBasicAction(name){
    if(baseActions[name]){
      baseActions[name].action.stop()
    }

  }

  function fadeToAction(name, duration) {
    if (baseActions[name] == activeAction) return
    // console.log("fadeToAction:",name);
    previousAction = activeAction
    activeAction = baseActions[name].action

    if (previousAction !== activeAction) {
      previousAction.fadeOut(duration)
    }

    activeAction.reset().setEffectiveTimeScale(1).setEffectiveWeight(1).fadeIn(duration).play()
  }

  function fadeActionWeight(name, weight,duration,goIn=true) {

    if(additiveActions[name]){

      // additiveActions[name].action.enabled = true;
      // additiveActions[name].action.loop = THREE.LoopOnce;
      if(goIn){
        additiveActions[name].action.reset().setEffectiveTimeScale(weight).setEffectiveWeight(weight).fadeIn(duration);
      }
      else {
        additiveActions[name].action.fadeOut(duration);
      }
    }
  }
  this.setSpeakData = function(dataList,msgData){
    speakDataList = dataList;
    messageData = msgData;
  }
  this.startSpeakByData = function(){
    if(speakDataIndex == 0){
      console.log('开始播放表情序列')
      console.log('当前序列表情index:',speakDataIndex)
      this.speakMouseByDataIndex(speakDataIndex);
      speakDataIndex+=1;
      
      
    }
    
  }
  this.speakMouseByDataIndex = async function(index){
    // if(messageData){
    //   emitter.emit(mittTypes.LIVEKIT.MESSAGE_VISEME_ACK_RETRUN,messageData)
    // }
    function speaknext(paticipant){
      // if(paticipant.isSpeaking){
      if(true){
        console.log('speakNextIndex')
        // emitter.off(mittTypes.LIVEKIT.PATICIPANT_SPEAKING,speaknext)
        mouseTime = 0;

        allMouseActions.forEach(function (action) {
          action.enable = true;
          action.weight = 0;
          action.play();
        })
      
        speaking = true;
        mouseData = speakDataList[index];
        //有返回动画的，需要获取最新的动画，存储到mouseMoves[]数组
        curMouseIndex = 0;
      }
    }
    // emitter.on(mittTypes.LIVEKIT.PATICIPANT_SPEAKING,speaknext)
    speaknext()
    // setTimeout(() => {
    //   mouseTime = 0;

    //   allMouseActions.forEach(function (action) {
    //     action.enable = true;
    //     action.weight = 0;
    //     action.play();
    //   })
    
    //   speaking = true;
    //   mouseData = speakDataList[index];
    //   //有返回动画的，需要获取最新的动画，存储到mouseMoves[]数组
    //   curMouseIndex = 0;
    //   // allMouseActions[mouseData[0].id].fadeIn(fadeTime);
    // }, 600);
    
    
  }
  
  this.speak = async function (text,ttsAudio) {

      console.log("role speak :"+text);

      if(sound.isPlaying){//旧的音频被中断
        sound.stop();
      }

      // const audio = await ttsApi({
      //   "text": text,
      //   "configJson":scope.sceneStore.projectData,
      //   "responseType":"arraybuffer"
      // })
      const audio = ttsAudio;
      // let blob = new Blob([audio], {type: 'audio/mpeg'})
      // let buffer = await blobToArrayBuffer(audio)
      const audioContext = new AudioContext();
      audioContext.decodeAudioData(audio, (audioBuffer) => {
          // Do something with audioBuffer
          console.log(audioBuffer)
          sound.setBuffer(audioBuffer);
			  	sound.setLoop(false);
			  	sound.setVolume(0.5);

			  	sound.play();

			  	analyser = new THREE.AudioAnalyser(sound, 32);



			  	///////眼睛动画
			  	//眼睛的于口型的有影响
			  	// eyeAction.enable=false;
			  	// eyeAction.stop();

			  	allMouseActions.forEach(function (action) {
			  		action.enable = true;
			  		action.weight = 0;
			  		action.play();
			  	})

			  	speaking = true;
			  	mouseTime = 0;
			  	//有返回动画的，需要获取最新的动画，存储到mouseMoves[]数组
			  	curMouse = mouseMoves[0];
			  	curMouseIndex = 0;
			  	// mouseActions[curMouse.id].weight=1;
			  	allMouseActions[curMouse.id].fadeIn(fadeTime);


			  // startAction.crossFadeTo( endAction, duration, true );
      })
			
	}
  this.clearSpeakData = function(){
    speakDataIndex = 0;
    speakDataList = [];
    audioElementList = [];
    messageData = null
  }
  this.stopSpeak=function(){
    if(sound.isPlaying){//旧的音频被中断
      sound.stop();
    }
    if(currentAudioElement){
      currentAudioElement.pause();
    }
    
    allMouseActions.forEach(action=>{
      action.weight=0;
      action.stop();
    })
    mouseData = null;
    speaking = false;
  }

  this.tick = function (delta) {
    for (let i = 0; i !== allActions.length; ++i) {
      const action = allActions[i]
      const clip = action.getClip()
      const settings = baseActions[clip.name] || additiveActions[clip.name]|| mouseActions[clip.name]
      settings.weight = action.getEffectiveWeight()
    }

    // let mixerUpdateDelta = clock.getDelta();

			let deltaTime = delta * 1000;//换算成毫秒

			/////根据实时语音播的
			if (analyser && speaking == true) {
				mouseTime += deltaTime;

				let fr = analyser.getAverageFrequency();
				// console.log("frequency:", fr);

				// let oldAction=mouseActions[curMouse.id];
				//进入下一个
				if (fr > 10 && mouseTime > 50) {
					mouseTime = 0;
					//旧的停止	
					if (oldAction)
						oldAction.stopFading();

					let num = parseInt(Math.random() * 8);
					let newAction = allMouseActions[num];

					newAction.time = 0;
					setWeight(newAction, 0.9);
					newAction._scheduleFading(0.3, newAction.weight, 1);
					if (oldAction)
						oldAction._scheduleFading(0.3, oldAction.weight, 0);

					oldAction = newAction;

					oldFr = fr;
				} else if (fr <= 10 && mouseTime > 50) {
					let newAction = allMouseActions[4];
					newAction.time = 0;
					setWeight(newAction, 0.9);
					newAction._scheduleFading(0.3, newAction.weight, 1);
					if (oldAction)
						oldAction._scheduleFading(0.3, oldAction.weight, 0);
					oldAction = newAction;
				}

				if (sound && sound.isPlaying == false) {

          // allMouseActions.forEach(action=>{
          //   action.weight=0;
          //   action.stop();
          // })

					// speaking = false;
          this.stopSpeak();
				}
			}
      if (speaking == true&&mouseData&&mouseData[curMouseIndex]) {
				mouseTime += delta*1000;
        let curOffset = mouseData[curMouseIndex].offset ;
        if(curOffset== undefined){
          curOffset =mouseData[curMouseIndex].audioOffset
        }
        let curVisemeId = mouseData[curMouseIndex].id ;
        if(curVisemeId== undefined){
          curVisemeId =mouseData[curMouseIndex].visemeId
        }
        if((mouseTime >= curOffset)){
          //旧的停止	
          // if (oldAction){
          //   oldAction.stopFading();
          // }
          

          let newAction = allMouseActions[curVisemeId];
          // console.log(mouseData[curMouseIndex].id)

          newAction.time = 0;
          let wight = 0.5+Math.random()*0.5
          setWeight(newAction, wight);
          let t
          if(curMouseIndex<(mouseData.length-1)){
            let nextOffset = mouseData[curMouseIndex+1].offset ;
            if(nextOffset== undefined){
              nextOffset =mouseData[curMouseIndex+1].audioOffset
            }
            t= (nextOffset-curOffset)/1000*2
          }else{
            t = 0.3
          }
          if(t<0.2)//平滑，使得口型不抖动
            t=0.2
          if(t>0.1){
            // wight = 0.5+Math.random()*0.5
            wight=t/0.3;//平滑，使得口型不抖动
            if(wight>1)
              wight=1
          }else{
            wight = 0.3+Math.random()*0.3
          }
          if (oldAction){
           
            // console.log("oldaction:%s，newaction:%s",oldAction.getClip().name,newAction.getClip().name)
            // console.log('交叉淡入时间: %f; 淡入权重: %f; 旧动作权重: %f,当前动作权重:%f', t, wight, oldAction.weight,newAction.weight)
          
            oldAction._scheduleFading(t, oldAction.weight, 0);
            newAction._scheduleFading(t, newAction.weight, wight);
          }else{
            newAction.fadeIn(t)
          }
          

          oldAction = newAction;
          curMouseIndex+=1;
          if(curMouseIndex>=mouseData.length){
            // mouseTime = 0;
            this.stopSpeak();
            if(speakDataIndex<=speakDataList.length){
              // setTimeout(() => {
                
              // }, 200);
              this.speakMouseByDataIndex(speakDataIndex)
                console.log('当前序列表情index:',speakDataIndex)
                console.log('当前序列表情总数:',speakDataList.length)
                speakDataIndex+=1;
              
            }
            
          }
        }

				// console.log("frequency:", fr);

				// let oldAction=mouseActions[curMouse.id];
				
			}
      // if(curAction){
      //   curAction.time = 0;
      //   setWeight(curAction, 0.9);
      //   curAction._scheduleFading(1, curAction.weight, 1);
      // }
      if(mixerEnable){
        mixer.update(delta)
      }
      

    // this.checkNearToPlay()
  }

  function activateAction(action) {
    const clip = action.getClip()
    const settings = baseActions[clip.name] || additiveActions[clip.name]||mouseActions[clip.name]
    setWeight(action, settings?settings.weight:0)
    action.play()
  }
  this.activateBaseActionByName = function(name,loopType,callback,noCross) {
    if(callback){
      actionFinCallback = callback;
    }
    allActions.forEach(function(action){
      if(action._clip.name == name){
        console.log('开始播放动作:', name); // 添加日志跟踪
        console.log('当前播放动作:', curAction); // 添加日志跟踪
        console.log('当前播放动作循环类型:', curAction.loop); // 添加日志跟踪
        console.log('当前播放动作是否过渡:',!noCross); // 添加日志跟踪
        
        action.setLoop(loopType);
        action.clampWhenFinished = true;
        setWeight(action, 1);
        if(noCross){
          stopBasicAction('idle')
          // _this.stopExtraAction(curAction.name)
          // action.reset();
          // action.paused = false;
          // action.time = 0
          action.play()
          action.fadeIn(0);
        }else{
          stopBasicAction('idle')
          action.reset();
          action.play()
          action.paused = false;
          action.time = 0
          // 不使用scheduleFading，直接设置权重
          if (curAction && curAction !== action) {
            action.crossFadeFrom(curAction, 0.3, true);
          } else {
            action.fadeIn(0.3);
          }
        }
        
        
        curAction = action;
        // action.play()
      }
    })
  }
  this.stopBaseAction = stopBasicAction
  function setWeight(action, weight) {
    action.enabled = true
    action.setEffectiveTimeScale(1)
    action.setEffectiveWeight(weight)
  }
  this.activeExtraAction = function(name,callback){
    console.log('开始播放动作:', name); // 添加日志跟踪
    if(callback){
      actionFinCallback = callback;
    }
    // 先停止所有可能影响的动作
    // allActions.forEach(function(action){
    //   if(action !== curAction && action.getEffectiveWeight() > 0) {
    //     action.fadeOut(0.2); // 快速淡出其他动作
    //   }
    // });
    
    let actionFound = false;
    allActions.forEach(function(action){
      if(action._clip.name == name){
        stopBasicAction('idle')
        actionFound = true;
        action.reset();
        action.setLoop(THREE.LoopOnce);
        action.play();
        action.paused = false;
        action.time = 0;
        
        // 确保权重设置为1，使动作完全可见
        setWeight(action, 1);
        
        // 不使用scheduleFading，直接设置权重
        if (curAction && curAction !== action) {
          action.crossFadeFrom(curAction, 0.3, true);
        } else {
          action.fadeIn(0.3);
        }
        
        curAction = action;
        console.log('动作已设置:', action._clip.name, '权重:', action.getEffectiveWeight());
      }
    });
    
    if (!actionFound) {
      console.warn('未找到动作:', name);
    }
    
    // 确保mixer启用
    mixerEnable = true;
  }
  this.setExtraActionByTime = function(name,time){
    console.log('设置动作时间:', name, time);
    
    // 先停止所有可能影响的动作
    // allActions.forEach(function(action){
    //   if(action !== curAction && action.getEffectiveWeight() > 0) {
    //     action.fadeOut(0.2);
    //   }
    // });
    
    let actionFound = false;
    allActions.forEach(function(action){
      if(action._clip.name == name){
        actionFound = true;
        action.reset();
        action.setLoop(THREE.LoopOnce);
        action.play();
        action.time = time;
        
        // 确保权重设置为1
        setWeight(action, 1);
        
        // 设置mixer时间
        mixer.setTime(time);
        
        // 不要暂停动作
        // action.paused = true; // 注释掉这行，可能是问题所在
        
        if (curAction && curAction !== action) {
          // 使用更短的交叉淡入时间
          action.crossFadeFrom(curAction, 0.1, true);
        }
        
        curAction = action;
        console.log('动作时间已设置:', action._clip.name, '时间:', time, '权重:', action.getEffectiveWeight());
      }
    });
    
    if (!actionFound) {
      console.warn('未找到动作:', name);
    }
    
    // 确保mixer启用
    mixerEnable = true;
  }
  this.stopExtraAction = function(name){
    allActions.forEach(function(action){
      if(action._clip.name == name){
         action.stop()
      }
    })
  }
  this.getActionByName = function(name){

    for(var i=0;i<allActions.length;i++){
      if(allActions[i]._clip.name == name){
        return allActions[i]
      }
    }
  }
  function modifyTimeScale(speed) {
    mixer.timeScale = speed
  }

  function prepareCrossFade(startAction, endAction, duration) {
    // If the current action is 'idle', execute the crossfade immediately;
    // else wait until the current action has finished its current loop

    if (currentBaseAction === 'idle' || !startAction || !endAction) {
      executeCrossFade(startAction, endAction, duration)
    } else {
      synchronizeCrossFade(startAction, endAction, duration)
    }

    // Update control colors

    if (endAction) {
      const clip = endAction.getClip()
      currentBaseAction = clip.name
    } else {
      currentBaseAction = 'None'
    }
  }

  function synchronizeCrossFade(startAction, endAction, duration) {
    mixer.addEventListener('loop', onLoopFinished)

    function onLoopFinished(event) {
      if (event.action === startAction) {
        mixer.removeEventListener('loop', onLoopFinished)

        executeCrossFade(startAction, endAction, duration)
      }
    }
  }

  function executeCrossFade(startAction, endAction, duration) {
    // Not only the start action, but also the end action must get a weight of 1 before fading
    // (concerning the start action this is already guaranteed in this place)

    if (endAction) {
      endAction.setLoop(THREE.LoopRepeat)
      setWeight(endAction, 1)
      endAction.time = 0

      if (startAction) {
        // Crossfade with warping

        startAction.crossFadeTo(endAction, duration, true)
      } else {
        // Fade in

        endAction.fadeIn(duration)
      }
    } else {
      // Fade out

      startAction.fadeOut(duration)
    }
  }

  this.dispose = function () {
    scope.model.traverse(function (object) {
      if (object.isMesh) {
        object.geometry.dispose()
        object.material.dispose()
      }
    })
    if (scope.titleSprite) {
      scope.titleSprite.material.dispose()
      scope.titleSprite.geometry.dispose()
    }
    if(scope.chatCamera){
      scope.chatCamera = null;
    }
    if(scope.chatRenderer){
      scope.chatRenderer.domElement.parentNode.removeChild(scope.chatRenderer.domElement)
      scope.chatRenderer = null;
    }
    
    root.remove(scope.model)
    loop.updatables.remove(scope)

    this.stopSpeak();
  }

}
export { Role }
